#ifndef _THREAD_HPP_
#define _THREAD_HPP_

#include <string>
#include <vector>

#include "base.hpp"
#include "tools.hpp"

namespace thread
{
	enum
	{
		iThreadSingleQueue = 0,
		iThreadMultipleQueue = 1
	};

	class Thread 
	{
		public :
			Thread(const char * name = "NonNameThread");
			virtual ~Thread();

			int start();

			std::string name() const { return _name; }
			
			int index() const { return _index; }
			void index(int idx) { _index = idx; }
			pthread_t id() const { return _id; }

		protected :
			virtual void run() = 0;

		private :
			static void * run(void * arg)
			{
				Thread * pThis = reinterpret_cast<Thread*>(arg);
				pThis->run();
				return 0;
			}
			
		private :
			bool _start_flag;
			int  _index;
			std::string _name;

			pthread_t _id;
	};

	template <typename _RequestType, typename _ResponseType, 
			 template <class> class _QueueType, int _Pattern = iThreadSingleQueue>
	class ThreadPool
	{
		public :
			typedef _RequestType RequestType;
			typedef _ResponseType ResponseType;
			typedef _QueueType<RequestType> RequestQueue;
			typedef RequestQueue* RequestQueuePtr;
			typedef _QueueType<ResponseType> ResponseQueue;
			typedef ResponseQueue* ResponseQueuePtr;
	
		public :
			ThreadPool(const char * name = "NonNameThreadPool");
			~ThreadPool()
			{
				std::vector<Thread*>::iterator iter = _thread_vec.begin();
				for (; iter != _thread_vec.end(); ++ iter)
				{
					SAFE_DELETE(*iter);
				}
				_thread_vec.clear();

				SAFE_DELETE(_response_queue);
				
				typename std::vector<RequestQueuePtr>::iterator iter2 = _request_queue_vec.begin();
				for (; iter2 != _request_queue_vec.end(); ++ iter2)
				{
					SAFE_DELETE(*iter2);
				}
			}

			int add_thread(Thread * pThread);

			void start()
			{
				std::vector<Thread*>::iterator iter = _thread_vec.begin();
				for (; iter != _thread_vec.end(); ++ iter)
				{
					(*iter)->start();
				}
			}

		public :
			void put_request(const RequestType & request)
			{
				single_assert();
				_request_queue_vec[0]->put(request);
			}

			template <typename _Hash>
				void put_request(const RequestType & request, _Hash hash_func)
				{
					multiple_assert();
					int index = hash_func(request, _request_queue_vec.size());
					assert(index >= 0 && index < int(_request_queue_vec.size()));
					_request_queue_vec[index]->put(request);
				}

			void get_request(RequestType & request)
			{
				single_assert();
				_request_queue_vec[0]->get(request);
			}

			void get_request(int index, RequestType & requestr)
			{
				multiple_assert();
				_request_queue_vec[index]->get(requestr);
			}

			void put_response(const ResponseType & response)
			{
				_response_queue->put(response);
			}
			void get_response(ResponseType & response)
			{
				_response_queue->get(response);
			}

			/// @NOTICE this function just use for debug log
			size_t request_size() const
			{
				single_assert();
				return _request_queue_vec[0]->size();
			}

			/// @NOTICE this function just use for debug log
			size_t request_size(int index) const
			{
				multiple_assert();
				return _request_queue_vec[index]->size();
			}

			/// @NOTICE this function just use for debug log
			size_t response_size() const
			{
				return _response_queue->size();
			}

			/// @NOTICE this function just use for debug log
			bool request_empty() const
			{
				single_assert();
				return _request_queue_vec[0]->empty();
			}

			/// @NOTICE this function just use for debug log
			bool request_empty(int index) const
			{
				multiple_assert();
				return _request_queue_vec[index]->empty();
			}

			/// @NOTICE this function just use for debug log
			bool response_empty() const
			{
				return _response_queue->empty();
			}

		private :
			void single_assert()
			{
				assert(iThreadSingleQueue == _Pattern);
			}

			void multiple_assert()
			{
				assert(iThreadMultipleQueue == _Pattern);
			}
		private :
			std::string _name;
			std::vector<Thread*> _thread_vec;
			std::vector<RequestQueuePtr> _request_queue_vec;
			ResponseQueuePtr _response_queue;
	};

	template <typename _RequestType, 
			 typename _ResponseType, 
			 template <class> class _QueueType,
			 int _Pattern>
	ThreadPool<_RequestType,
			 _ResponseType,
			 _QueueType,
			 _Pattern>::ThreadPool(const char * name)
			 {
				 _name = name;
				 _request_queue_vec.clear();

				 if (iThreadSingleQueue == _Pattern)
				 {
					 _request_queue_vec.push_back(new RequestQueue);
				 }

				 _response_queue = new ResponseQueue;
			 }

	template <typename _RequestType, 
			 typename _ResponseType, 
			 template <class> class _QueueType,
			 int _Pattern>
	int ThreadPool<_RequestType,
				 _ResponseType,
				 _QueueType,
				 _Pattern>::add_thread(Thread * pThread)
				{
					if (iThreadMultipleQueue == _Pattern)
					{
						RequestQueuePtr queue = new RequestQueue;
						_request_queue_vec.push_back(queue);
					}
					
					int idx = _thread_vec.size();
					pThread->index(idx);
					_thread_vec.push_back(pThread);

					return idx;
				}
}

#endif

